package eerbaar.position.internal;

import java.util.ArrayList;
import java.util.List;

import eerbaar.position.IPosition;
import eerbaar.position.IPositionListener;
import eerbaar.position.WrongPositionException;

public class Position implements IPosition {

    private final List<IPositionListener> listeners = new ArrayList<IPositionListener>();

    private int x;

    private int y;

    public Position() {
        //
    }

    public Position(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public Position(IPosition copy) {
        this.x = copy.getX();
        this.y = copy.getY();
    }

    @Override
    public void add(int x, int y) throws WrongPositionException {

        Position start = new Position(this);
        Position copy = new Position(this);
        copy.x += x;
        copy.y += y;
        fireBeforePositionChange(copy);
        this.x += x;
        this.y += y;
        fireAfterPositionChange(start);
    }

    @Override
    public void addListener(IPositionListener listener) {
        if (!this.listeners.contains(listener)) {
            this.listeners.add(listener);
        }
    }

    @Override
    public void decrementX() throws WrongPositionException {

        Position start = new Position(this);
        Position copy = new Position(this);
        copy.x--;
        fireBeforePositionChange(copy);
        this.x--;
        fireAfterPositionChange(start);
    }

    @Override
    public void decrementY() throws WrongPositionException {

        Position start = new Position(this);
        Position copy = new Position(this);
        copy.y--;
        fireBeforePositionChange(copy);
        this.y--;
        fireAfterPositionChange(start);
    }

    @Override
    public boolean equals(Object obj) {

        Position other = (Position) obj;
        return (other.x == this.x && other.y == this.y);
    }

    private void fireAfterPositionChange(IPosition oldPos) {
        List<IPositionListener> temp = new ArrayList<IPositionListener>();
        temp.addAll(this.listeners);
        for (IPositionListener listener : temp) {
            listener.afterPositionChange(oldPos, this);
        }
    }

    private void fireBeforePositionChange(Position position)
            throws WrongPositionException {

        for (IPositionListener listener : this.listeners) {
            listener.beforePositionChange(position);
        }
    }

    @Override
    public int getX() {
        return this.x;
    }

    @Override
    public int getY() {
        return this.y;
    }

    @Override
    public int hashCode() {

        return toString().hashCode();
    }

    @Override
    public void incrementX() throws WrongPositionException {

        Position start = new Position(this);
        Position copy = new Position(this);
        copy.x++;
        fireBeforePositionChange(copy);
        this.x++;
        fireAfterPositionChange(start);
    }

    @Override
    public void incrementY() throws WrongPositionException {

        Position start = new Position(this);
        Position copy = new Position(this);
        copy.y++;
        fireBeforePositionChange(copy);
        this.y++;
        fireAfterPositionChange(start);
    }

    @Override
    public void removeListener(IPositionListener listener) {

        this.listeners.remove(listener);
    }

    @Override
    public void set(int x, int y) throws WrongPositionException {

        if (x == this.x && y == this.y) {
            return;
        }

        Position copy = new Position(this);
        copy.x = x;
        copy.y = y;
        fireBeforePositionChange(copy);
        this.x = x;
        this.y = y;
        fireAfterPositionChange(copy);
    }

    @Override
    public String toString() {

        return "position(" + this.x + "," + this.y + ")";
    }
}
